﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web.Configuration;
using System.Linq;
using System.Text;
using JQuery.Net;
using System.ComponentModel;

namespace JQuery 
{
    public enum PluginConfigSection
    {
        gadget,
        dock,
        jquery,
        mvc
    }

    public class JQNConfigSection
        : ConfigurationSection
    {
        #region "constructors"
        public JQNConfigSection()
            : base() { }
        #endregion

        #region "section constants"
        private const string MEFSUPPORT = "EnablePlugins";
        private const string ASSEMBLIES = "Plugins";
        private const string OPTIMIZE = "OptimizeScripts";
        private const string MINIMIZE = "MinimizeScripts";
        private const string SETTINGS = "Configuration";
        #endregion

        #region "properties"
        [ConfigurationProperty(MEFSUPPORT, DefaultValue = true, IsRequired = true)]
        public bool EnablePlugins { get { return (bool)this[MEFSUPPORT]; } }
        [ConfigurationProperty(OPTIMIZE, DefaultValue = true, IsRequired = false)]
        public bool IsOptimized { get { return (bool)this[OPTIMIZE]; } }
        [ConfigurationProperty(MINIMIZE, DefaultValue = true, IsRequired = false)]
        public bool IsMinimized { get { return (bool)this[MINIMIZE]; } }
        
        [ConfigurationProperty(ASSEMBLIES, IsDefaultCollection = false)]
        [ConfigurationCollection(typeof(PluginCollection), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
        public PluginCollection Plugins { get { return (PluginCollection)this[ASSEMBLIES]; } }
        [ConfigurationProperty(SETTINGS, IsDefaultCollection = false)]
        [ConfigurationCollection(typeof(PluginConfigCollection), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
        public PluginConfigCollection Configuration { get { return (PluginConfigCollection)this[SETTINGS]; } }
        #endregion
    }

    public class PluginCollection
        : ConfigurationElementCollection
    {
        #region "constructor"
        public PluginCollection()
            : base() { }
        #endregion

        #region "indexer"
        public new PluginElement this[string name]
        {
            get { return (PluginElement)BaseGet(name); }
        }
        #endregion

        protected override ConfigurationElement CreateNewElement()
        {
            return new PluginElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((PluginElement)element).AssemblyFullName;
        }
    }

    public class PluginConfigCollection
        : ConfigurationElementCollection
    {
        #region indexer
        public PluginConfigElement this[PluginConfigSection config]
        {
            get
            {
                return (PluginConfigElement)BaseGet(config);
            }
        }
        #endregion

        protected override ConfigurationElement CreateNewElement()
        {
            return new PluginConfigElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((PluginConfigElement)element).ID;
        }
    }

    public class PluginSettingsCollection
        : ConfigurationElementCollection
    {
        #region indexer
        public new PluginSettingElement this[string setting]
        {
            get { return (PluginSettingElement)BaseGet(setting); }
        }
        #endregion

        protected override ConfigurationElement CreateNewElement()
        {
            return new PluginSettingElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((PluginSettingElement)element).Name;
        }
    }

    public class PluginElement
        : ConfigurationElement
    {
        #region "constructors"
        public PluginElement(string name)
            : this()
        {
            this.AssemblyFullName = name;
        }

        public PluginElement()
            : base() { }
        #endregion

        [ConfigurationProperty("type", IsRequired = true)]
        public string AssemblyFullName { get { return (string)this["type"]; } set { this["type"] = value; } }
    }

    public class PluginConfigElement
        : ConfigurationElement
    {
        #region "constructors"
        public PluginConfigElement()
            : base() { }
        #endregion

        #region constants
        private struct keys
        {
            public const string id = "id";
            public const string settings = "settings";
        }
        #endregion

        #region indexer
        public new PluginSettingElement this[string setting]
        {
            get
            {
                return Settings[setting];
            }
        }
        #endregion

        [ConfigurationProperty(keys.id, IsKey = true, IsRequired = true)]
        public PluginConfigSection ID
        {
            get
            {
                ConfigurationProperty property = new ConfigurationProperty(keys.id, typeof(PluginConfigSection));
                return (PluginConfigSection)this[property];//Enum.Parse(typeof(PluginConfigSection), (string)this[property], true);
            }
            set
            {
                ConfigurationProperty property = new ConfigurationProperty(keys.id, typeof(PluginConfigSection));
                this[property] = Enum.GetName(value.GetType(), value);
            }
        }
        [ConfigurationProperty(keys.settings, IsDefaultCollection = true)]
        [ConfigurationCollection(typeof(PluginSettingsCollection), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
        public PluginSettingsCollection Settings { get { return (PluginSettingsCollection)this[new ConfigurationProperty(keys.settings, typeof(PluginSettingsCollection))]; } }

        public string GetSettingValue(string setting)
        {
            return Settings[setting].IsNotNull((X) =>
                X.Value);
        }

        public void SetSettingValue(string setting, string value)
        {
            if (Settings[setting] != null)
            {
                Settings[setting].Value = value;
            }
        }
    }

    public class PluginSettingElement
        : ConfigurationElement
    {
        #region constants
        private struct keys
        {
            public const string name = "name";
            public const string value = "value";
            public const string type = "type";
        }
        #endregion

        [ConfigurationProperty(keys.name, IsKey = true, IsRequired = true)]
        public string Name { get { return (string)this[keys.name]; } set { this[keys.name] = value; } }
        [ConfigurationProperty(keys.value, IsRequired = true)]
        public string Value { get { return (string)this[keys.value]; } set { this[keys.value] = value; } }
        [ConfigurationProperty(keys.type), TypeConverter(typeof(ConfigTypeConverter))]
        public Type Type
        {
            get { return (Type)this[keys.type]; }
            set { this[keys.type] = value; }
        }
    }

    internal class ConfigTypeConverter
        : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType.Equals(typeof(string));
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            return Type.GetType((string)value, false, true);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType.Equals(typeof(string));
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            return destinationType.Equals(typeof(string))
                ? ((Type)value).AssemblyQualifiedName
                : String.Empty;
        }
    }
}
